<?php


namespace App\Imports;

use App\Exceptions\ApiException;
use App\Services\BaseService;
use App\Services\BookCatalogService;
use App\Services\BookTitleService;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Events\AfterImport;

/**
 * Class BookCatalogImportA
 * @package App\Imports
 * 下面发现个现象 BookCatalogImportA 如果 implements  SkipsEmptyRows会导致  WithStartRow 失效
 */
class BookCatalogImport8 implements ToModel, WithStartRow, WithColumnLimit, WithEvents
{
    protected $stop;
    protected $partCompanyId;
    protected $startRow;
    protected $endColumn;
    protected $redisExpireTime;
    protected $bookTitleInstance;
    protected $bookCatalogInstance;
    protected $bookTitleIdKey;
    protected $archivesNoKey;
    protected $importCountKey;

    /**
     * 如果一个档案号 20秒内出现多次，直接视为一个档案号多页写入数据，不进行覆盖
     */
    public function __construct($partCompanyId, $projectClassifyId, $importCountKey)
    {
        $this->partCompanyId       = $partCompanyId;
        $this->projectClassifyId   = $projectClassifyId;
        $this->importCountKey      = $importCountKey;
        $this->stop                = 0;
        $this->startRow            = 1;   //从第几行开始
        $this->endColumn           = 'E'; //指定到那一列为止
        $this->bookTitleIdKey      = 'bookTitleIdKey:' . $importCountKey;
        $this->archivesNoKey       = 'archivesNoKey:' . $importCountKey;
        $this->linkBtIdsKey        = 'linkBtIdsKey:' . $importCountKey;
        $this->redisExpireTime     = 5; //把档案号存起来，如果5秒内出现重复的档案号，直接认为是追加数据，而不是覆盖
        $this->bookTitleInstance   = (new BaseService())->getBookTitleInstance($partCompanyId, $projectClassifyId);
        $this->bookCatalogInstance = (new BaseService())->getBookCatalogInstance($partCompanyId, $projectClassifyId);
    }

    public function model(array $row)
    {
        if (!(empty($row[0]) && empty($row[1]))) { //不同时为空，就视为有数据

            if ($row[0] == 'ee') $this->stop = 1; //如果出现了指定【终止标识】，不在写入

            if (str_contains(trim($row[0]), '档案号：')) { //第一种格式：有档案号
                $archivesNo = mb_substr(trim($row[0]), 4);
                $archivesNo = format_archives_no(trim($archivesNo));
                self::cacheBookTitleId($archivesNo);
            }
            $archivesNo = redis()->get($this->archivesNoKey);
            if (!empty($archivesNo)) {

                $bookTitleId = redis()->get($this->bookTitleIdKey);

                redis()->sadd($this->linkBtIdsKey, $bookTitleId); //用作更新字段catalog_count备用

                if (empty($bookTitleId)) {
                    throw new ApiException("找不到档案号 {$row[0]}！格式存在错误");
                }
                if (is_numeric($row[0])) { //只写入序号为数字的例如 1、2、3....
                    redis()->incr($this->importCountKey);
                    $this->bookCatalogInstance->insert([
                        'book_title_id' => $bookTitleId,
                        'serial_no'     => $row[0],                  //序号
                        'file_number'   => format_str($row[1]),      //图号或文件编号
                        'title'         => format_str($row[2]),      //文件材料题名
                        'page_num'      => format_page_num($row[3]), //张次
                        'remark'        => format_str($row[4]),      //备注
                        'created_at'    => now(),
                        'updated_at'    => now(),
                        'creator_id'    => user_id(),
                    ]);
                }
            }
        }
    }

    /**
     * 使用档案号查询案卷目录id，查出后进行缓存
     */
    private function cacheBookTitleId($archivesNo)
    {
        if ($archivesNo && (redis()->get($this->archivesNoKey) != $archivesNo)) { //如果10秒内档案号一致，继续写入，不覆盖
            $bookTitleId = $this->bookTitleInstance->where('archives_no', $archivesNo)->value('id');
            if (empty($bookTitleId)) {
                throw new ApiException('找不到档案号：' . $archivesNo.',档案号必须已存在于系统。或者是否有隐藏的sheet表格？请尝试新建个xlsx文件,并复制所需数据 或者 刷新下页面！');
            }
            redis()->setex($this->archivesNoKey, $this->redisExpireTime, $archivesNo); //把档案号存起来
            redis()->setex($this->bookTitleIdKey, $this->redisExpireTime, $bookTitleId); //暂存案卷目录id

            $this->bookTitleInstance->where('id', $bookTitleId)->update(['is_have_data' => 1, 'is_need_check' => 1]); //更新为有数据,需要检查

            $catalogIds = $this->bookCatalogInstance->where('book_title_id', $bookTitleId)->pluck('id');
            if ($catalogIds->isNotEmpty()) { //把卷内PDF也删了
                $catalogIds = $catalogIds->toArray();
                (new BookCatalogService())->delCatalogPdf($this->partCompanyId, $this->projectClassifyId, $catalogIds);
            }

            $this->bookCatalogInstance->where('book_title_id', $bookTitleId)->delete();
        }
    }

    /**
     * 直接过滤表头，第一块数据含表头
     *
     * @return int
     */
    public function startRow(): int
    {
        return $this->startRow;
    }

    /**
     * 指定到那一列为止，G代表读取到G列就不再读取
     *
     * @return string
     */
    public function endColumn(): string
    {
        return $this->endColumn;
    }

    /**
     * excel导入完毕后执行的方法
     *
     * @return \Closure[]
     * @author: lxk
     * @date: 2024-11-16 14:47
     */
    public function registerEvents(): array
    {
        $partCompanyId     = $this->partCompanyId;
        $projectClassifyId = $this->projectClassifyId;
        $linkBtIdsKey      = $this->linkBtIdsKey;
        return [
            AfterImport::class => function (AfterImport $event) use ($partCompanyId, $projectClassifyId, $linkBtIdsKey) {
                $bookTitleIds = redis()->smembers($linkBtIdsKey); //获取涉及到的案卷id，更新卷内数据
                BookTitleService::updateCatalogCount($partCompanyId, $projectClassifyId, $bookTitleIds);
                redis()->del($linkBtIdsKey);
            }
        ];
    }


}
